package com.maibow.util.weixin;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Formatter;
import java.util.Properties;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.maibow.entity.weixin.AccessToken;
import com.maibow.entity.weixin.OpenIdInfo;
import com.maibow.entity.weixin.WeixinTicket;
import com.maibow.entity.weixin.WeixinUserInfo;
import com.maibow.util.Logger;
import com.maibow.util.PropertiesUtil;
import com.sun.jmx.snmp.Timestamp;

public class WeixinUtil {
    protected Logger logger = Logger.getLogger(this.getClass());

    /**
     * 
     * getAccessToken(这里用一句话描述这个方法的作用)
     * (这里描述这个方法适用条件 – 可选)
     * 标记：@param appid
     * 标记：@param appsecret
     * 标记：@return
     * 标记：@throws Exception
     * 标记：@throws IOException
     * 返回值：AccessToken
     * 作者：吴比(Wubi)
     * 
     * @exception
     * @since 1.0.0
     */
    public AccessToken getAccessToken(String appid, String appsecret) throws Exception, IOException {
        AccessToken accessToken = new AccessToken();
        try {
            Properties prop = System.getProperties();
            String os = prop.getProperty("os.name");
            String path = null;
            if (os.startsWith("Win")) {
                path = (String.valueOf(Thread.currentThread().getContextClassLoader().getResource(""))).replaceAll("file:/", "").replaceAll("%20", " ").trim();
            } else {
                path = (String.valueOf(Thread.currentThread().getContextClassLoader().getResource(""))).replaceAll("file:", "").replaceAll("%20", " ").trim();
            }

            PropertiesUtil putil = new PropertiesUtil(path + WeixinConstants.CONF_PROPERTIES_PATH);
            Long overduetime = Long.parseLong(putil.getProperty("OVERDUE_ACCESS_TOKEN_TIME"));
            Timestamp s = new Timestamp();
            if (s.getDateTime() > overduetime) {
                JsonParser jsonparer = new JsonParser();// 初始化解析json格式的对象
                String requestUrl = WeixinConstants.GET_ACCESSTOKEN_URL.replace("CHUXIAN_PARTY_APPID", appid).replace("APPSECRET", appsecret);
                HttpClient client = new DefaultHttpClient();
                HttpGet get = new HttpGet(requestUrl);
                HttpResponse res = client.execute(get);
                String responseContent = null; // 响应内容
                HttpEntity entity = res.getEntity();
                responseContent = EntityUtils.toString(entity, "UTF-8");
                JsonObject json = jsonparer.parse(responseContent).getAsJsonObject();
                // JSONObject jsonObject =
                // JSONObject.fromObject(json);
                // 如果请求成功
                if (null != json) {
                    try {
                        accessToken.setAccessToken(json.get("access_token").getAsString());
                        accessToken.setExpiresIn(json.get("expires_in").getAsInt());
                    } catch (Exception e) {
                        accessToken = null;
                        // 获取token失败
                        logger.debug("获取token失败 errcode:{} errmsg:{}");
                    }
                }
                putil.writeProperties("OVERDUE_ACCESS_TOKEN_TIME", String.valueOf(s.getDateTime() + WeixinConstants.EFFECTIVE_TIME));
                putil.writeProperties("ACCESS_TOKEN", accessToken.getAccessToken());
            } else {
                logger.debug("token:" + putil.getProperty("ACCESS_TOKEN") + ",time:" + putil.getProperty("OVERDUE_ACCESS_TOKEN_TIME"));
                accessToken.setAccessToken(putil.getProperty("ACCESS_TOKEN"));
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return accessToken;
    }

    /**
     * 
     * getAccessTokenV2(这里用一句话描述这个方法的作用)
     * (这里描述这个方法适用条件 – 可选)
     * 标记：@param appid
     * 标记：@param appsecret
     * 标记：@return
     * 标记：@throws Exception
     * 标记：@throws IOException
     * 返回值：AccessToken
     * 作者：吴比(Wubi)
     * 
     * @exception
     * @since 1.0.0
     */
    public AccessToken getAccessTokenV2(String appid, String appsecret) throws Exception, IOException {
        AccessToken accessToken = new AccessToken();
        try {
            Properties prop = System.getProperties();
            String os = prop.getProperty("os.name");
            String path = null;
            if (os.startsWith("Win")) {
                path = (String.valueOf(Thread.currentThread().getContextClassLoader().getResource(""))).replaceAll("file:/", "").replaceAll("%20", " ").trim();
            } else {
                path = (String.valueOf(Thread.currentThread().getContextClassLoader().getResource(""))).replaceAll("file:", "").replaceAll("%20", " ").trim();
            }

            PropertiesUtil putil = new PropertiesUtil(path + WeixinConstants.CONF_PROPERTIES_PATH);
            Long overduetime = Long.parseLong(putil.getProperty("OVERDUE_ACCESS_TOKEN_TIME_V2"));
            Timestamp s = new Timestamp();
            if (s.getDateTime() > overduetime) {
                JsonParser jsonparer = new JsonParser();// 初始化解析json格式的对象
                String requestUrl = WeixinConstants.GET_ACCESSTOKEN_URL.replace("CHUXIAN_PARTY_APPID", appid).replace("APPSECRET", appsecret);
                HttpClient client = new DefaultHttpClient();
                HttpGet get = new HttpGet(requestUrl);
                HttpResponse res = client.execute(get);
                String responseContent = null; // 响应内容
                HttpEntity entity = res.getEntity();
                responseContent = EntityUtils.toString(entity, "UTF-8");
                JsonObject json = jsonparer.parse(responseContent).getAsJsonObject();
                // JSONObject jsonObject =
                // JSONObject.fromObject(json);
                // 如果请求成功
                if (null != json) {
                    try {
                        accessToken.setAccessToken(json.get("access_token").getAsString());
                        accessToken.setExpiresIn(json.get("expires_in").getAsInt());
                    } catch (Exception e) {
                        accessToken = null;
                        // 获取token失败
                        logger.debug("获取token失败 errcode:{} errmsg:{}");
                    }
                }
                putil.writeProperties("OVERDUE_ACCESS_TOKEN_TIME_V2", String.valueOf(s.getDateTime() + WeixinConstants.EFFECTIVE_TIME));
                putil.writeProperties("ACCESS_TOKEN_V2", accessToken.getAccessToken());
            } else {
                logger.debug("token:" + putil.getProperty("ACCESS_TOKEN_V2") + ",time:" + putil.getProperty("OVERDUE_ACCESS_TOKEN_TIME_V2"));
                accessToken.setAccessToken(putil.getProperty("ACCESS_TOKEN_V2"));
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return accessToken;
    }

    /**
     * 
     * getAccessTokenV3(这里用一句话描述这个方法的作用)
     * (这里描述这个方法适用条件 – 可选)
     * 标记：@param appid
     * 标记：@param appsecret
     * 标记：@return
     * 标记：@throws Exception
     * 标记：@throws IOException
     * 返回值：AccessToken
     * 作者：吴比(Wubi)
     * 
     * @exception
     * @since 1.0.0
     */
    public AccessToken getAccessTokenV3(String appid, String appsecret) throws Exception, IOException {
        AccessToken accessToken = new AccessToken();
        try {
            JsonParser jsonparer = new JsonParser();// 初始化解析json格式的对象
            String requestUrl = WeixinConstants.GET_ACCESSTOKEN_URL.replace("CHUXIAN_PARTY_APPID", appid).replace("APPSECRET", appsecret);
            HttpClient client = new DefaultHttpClient();
            HttpGet get = new HttpGet(requestUrl);
            HttpResponse res = client.execute(get);
            String responseContent = null; // 响应内容
            HttpEntity entity = res.getEntity();
            responseContent = EntityUtils.toString(entity, "UTF-8");
            JsonObject json = jsonparer.parse(responseContent).getAsJsonObject();
            // JSONObject jsonObject =
            // JSONObject.fromObject(json);
            // 如果请求成功
            if (null != json) {
                try {
                    accessToken.setAccessToken(json.get("access_token").getAsString());
                    accessToken.setExpiresIn(json.get("expires_in").getAsInt());
                } catch (Exception e) {
                    accessToken = null;
                    // 获取token失败
                    logger.debug("获取token失败 errcode:{} errmsg:{}");
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return accessToken;
    }

    public OpenIdInfo getOpenIdV2(String code) throws Exception, IOException {
        OpenIdInfo openIdInfo = new OpenIdInfo();
        try {
            // 超时从新获取accessToken
            JsonParser jsonparer = new JsonParser();// 初始化解析json格式的对象
            String requestUrl = WeixinConstants.GET_OPENID_URL.replace("CHUXIAN_PARTY_APPID", WeixinConstants.CHUXIAN_PARTY_APPID).replace("APPSECRET", WeixinConstants.CHUXIAN_PARTY_SECRET)
                                .replace("CODE", code);
            HttpClient client = new DefaultHttpClient();
            HttpGet get = new HttpGet(requestUrl);
            HttpResponse res = client.execute(get);
            String responseContent = null; // 响应内容
            HttpEntity entity = res.getEntity();
            responseContent = EntityUtils.toString(entity, "UTF-8");
            JsonObject json = jsonparer.parse(responseContent).getAsJsonObject();
            // JSONObject jsonObject =
            // JSONObject.fromObject(json);
            // 如果请求成功
            if (null != json) {
                try {
                    openIdInfo = new OpenIdInfo();
                    openIdInfo.setAccessToken(json.get("access_token").getAsString());
                    openIdInfo.setExpiresIn(json.get("expires_in").getAsInt());
                    openIdInfo.setOpenId(json.get("openid").getAsString());
                    openIdInfo.setRefreshToken(json.get("refresh_token").getAsString());
                    openIdInfo.setScope(json.get("scope").getAsString());
                } catch (Exception e) {
                    openIdInfo = null;
                    // 获取token失败
                    logger.debug("获取token失败 errcode:{} errmsg:{}" + json);
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return openIdInfo;
    }

    /**
     * 获取open_idV2
     * getOpenIdV3(这里用一句话描述这个方法的作用)
     * (这里描述这个方法适用条件 – 可选)
     * 标记：@param code
     * 标记：@return
     * 标记：@throws Exception
     * 标记：@throws IOException
     * 返回值：OpenIdInfo
     * 作者：吴比(Wubi)
     * 
     * @exception
     * @since 1.0.0
     */
    public OpenIdInfo getOpenIdV3(String code) throws Exception, IOException {
        OpenIdInfo openIdInfo = new OpenIdInfo();
        try {
            // 超时从新获取accessToken
            JsonParser jsonparer = new JsonParser();// 初始化解析json格式的对象
            String requestUrl = WeixinConstants.GET_OPENID_URL.replace("CHUXIAN_PARTY_APPID", WeixinConstants.CHUXIAN_PARTY_APPID).replace("APPSECRET", WeixinConstants.CHUXIAN_PARTY_SECRET)
                                .replace("CODE", code);
            HttpClient client = new DefaultHttpClient();
            HttpGet get = new HttpGet(requestUrl);
            HttpResponse res = client.execute(get);
            String responseContent = null; // 响应内容
            HttpEntity entity = res.getEntity();
            responseContent = EntityUtils.toString(entity, "UTF-8");
            JsonObject json = jsonparer.parse(responseContent).getAsJsonObject();
            // JSONObject jsonObject =
            // JSONObject.fromObject(json);
            // 如果请求成功
            if (null != json) {
                try {
                    openIdInfo = new OpenIdInfo();
                    openIdInfo.setAccessToken(json.get("access_token").getAsString());
                    openIdInfo.setExpiresIn(json.get("expires_in").getAsInt());
                    openIdInfo.setOpenId(json.get("openid").getAsString());
                    openIdInfo.setRefreshToken(json.get("refresh_token").getAsString());
                    openIdInfo.setScope(json.get("scope").getAsString());
                } catch (Exception e) {
                    openIdInfo = null;
                    // 获取token失败
                    logger.debug("获取token失败 errcode:{} errmsg:{}" + json);
                }
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return openIdInfo;
    }

    /**
     * 
     * getUserInfoId(这里用一句话描述这个方法的作用)
     * (这里描述这个方法适用条件 – 可选)
     * 标记：@param appid
     * 标记：@param appsecret
     * 标记：@param code
     * 标记：@return
     * 标记：@throws Exception
     * 标记：@throws IOException
     * 返回值：OpenIdInfo
     * 作者：吴比(Wubi)
     * 
     * @exception
     * @since 1.0.0
     */
    private WeixinUserInfo getWeixinUserInfoId(String access_token, String open_id) throws Exception, IOException {
        WeixinUserInfo weixinUserInfo = null;
        JsonParser jsonparer = new JsonParser();// 初始化解析json格式的对象
        String requestUrl = WeixinConstants.GET_USERINFO_URL.replace("ACCESSTOKEN", access_token).replace("OPENID", open_id);
        HttpClient client = new DefaultHttpClient();
        HttpGet get = new HttpGet(requestUrl);
        HttpResponse res = client.execute(get);
        String responseContent = null; // 响应内容
        HttpEntity entity = res.getEntity();
        responseContent = EntityUtils.toString(entity, "UTF-8");
        JsonObject json = jsonparer.parse(responseContent).getAsJsonObject();
        // JSONObject jsonObject =
        // JSONObject.fromObject(json);
        // 如果请求成功
        if (null != json) {
            try {
                weixinUserInfo = new WeixinUserInfo();
                weixinUserInfo.setNickName(json.get("nickname").getAsString());
                weixinUserInfo.setSex(json.get("sex").getAsInt());
                weixinUserInfo.setOpenId(json.get("openid").getAsString());
                weixinUserInfo.setHeadimgurl(json.get("headimgurl").getAsString());
                weixinUserInfo.setCountry(json.get("country").getAsString());
                weixinUserInfo.setProvince(json.get("province").getAsString());
                weixinUserInfo.setCity(json.get("city").getAsString());
                weixinUserInfo.setUnionid(json.get("unionid").getAsString());
            } catch (Exception e) {
                weixinUserInfo = null;
                // 获取token失败
                logger.debug("获取token失败 errcode:{} errmsg:{}" + json);
            }
        }
        return weixinUserInfo;
    }

    /**
     * 
     * getWeixinInfoByCode(这里用一句话描述这个方法的作用)
     * (这里描述这个方法适用条件 – 可选)
     * 标记：@param openIdInfo
     * 标记：@return
     * 返回值：WeixinUserInfo
     * 作者：吴比(Wubi)
     * 
     * @exception
     * @since 1.0.0
     */
    public WeixinUserInfo getWeixinInfoByCode(OpenIdInfo openIdInfo) {
        WeixinUserInfo weixinUserInfo = new WeixinUserInfo();
        try {
            weixinUserInfo = getWeixinUserInfoId(openIdInfo.getAccessToken(), openIdInfo.getOpenId());
            logger.debug(weixinUserInfo.getNickName() + weixinUserInfo.getHeadimgurl());
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return weixinUserInfo;
    }

    public final static String getMessageDigest(byte[] buffer) {
        char hexDigits[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(buffer);
            byte[] md = mdTemp.digest();
            int j = md.length;
            char str[] = new char[j * 2];
            int k = 0;
            for (int i = 0; i < j; i++) {
                byte byte0 = md[i];
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            return null;
        }
    }

    public final static String getMessageDigestV2(String string1) throws NoSuchAlgorithmException, UnsupportedEncodingException {
        MessageDigest crypt = MessageDigest.getInstance("SHA-1");
        crypt.reset();
        crypt.update(string1.getBytes("UTF-8"));
        return byteToHex(crypt.digest());
    }

    private static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    /**
     * 
     * getTicket(这里用一句话描述这个方法的作用)
     * (这里描述这个方法适用条件 – 可选)
     * 标记：@param accessToken
     * 标记：@return
     * 标记：@throws Exception
     * 标记：@throws IOException
     * 返回值：WeixinTicket
     * 作者：吴比(Wubi)
     * 
     * @exception
     * @since 1.0.0
     */
    public WeixinTicket getTicket(String accessToken) throws Exception, IOException {
        WeixinTicket weixinTicket = new WeixinTicket();
        try {
            Properties prop = System.getProperties();
            String os = prop.getProperty("os.name");
            String path = null;
            if (os.startsWith("Win")) {
                path = (String.valueOf(Thread.currentThread().getContextClassLoader().getResource(""))).replaceAll("file:/", "").replaceAll("%20", " ").trim();
            } else {
                path = (String.valueOf(Thread.currentThread().getContextClassLoader().getResource(""))).replaceAll("file:", "").replaceAll("%20", " ").trim();
            }

            PropertiesUtil putil = new PropertiesUtil(path + WeixinConstants.CONF_PROPERTIES_PATH);
            Long overduetime = Long.parseLong(putil.getProperty("OVERDUE_WEIXIN_TICKET_TIME"));
            Timestamp s = new Timestamp();
            if (s.getDateTime() > overduetime) {
                JsonParser jsonparer = new JsonParser();// 初始化解析json格式的对象
                String requestUrl = WeixinConstants.GET_WEIXINTICKET_URL.replace("ACCESS_TOKEN", accessToken);
                HttpClient client = new DefaultHttpClient();
                HttpGet get = new HttpGet(requestUrl);
                HttpResponse res = client.execute(get);
                String responseContent = null; // 响应内容
                HttpEntity entity = res.getEntity();
                responseContent = EntityUtils.toString(entity, "UTF-8");
                JsonObject json = jsonparer.parse(responseContent).getAsJsonObject();
                // 如果请求成功
                if (null != json) {
                    try {
                        weixinTicket.setTicket(json.get("ticket").getAsString());
                        weixinTicket.setExpiresIn(json.get("expires_in").getAsInt());
                    } catch (Exception e) {
                        accessToken = null;
                        // 获取token失败
                        logger.debug("获取token失败 errcode:{} errmsg:{}");
                    }
                }
                putil.writeProperties("OVERDUE_WEIXIN_TICKET_TIME", String.valueOf(s.getDateTime() + WeixinConstants.EFFECTIVE_TIME));
                putil.writeProperties("WEIXIN_TICKET", weixinTicket.getTicket());
            } else {
                logger.debug("token:" + putil.getProperty("WEIXIN_TICKET") + ",time:" + putil.getProperty("OVERDUE_WEIXIN_TICKET_TIME"));
                weixinTicket.setTicket(putil.getProperty("WEIXIN_TICKET"));
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }
        return weixinTicket;
    }

    public static void main(String[] args) {
        WeixinUtil util = new WeixinUtil();
        try {
            // 获取accessToken之前判断文件里有没有，没有重新获取，填写过期时间，有判断时间有没有过期
            // AccessToken token = new
            // AccessToken();
            // 超时从新获取accessToken
            // token =
            // util.getAccessToken2(WeixinConstants.CHUXIAN_PARTY_APPID,
            // WeixinConstants.CHUXIAN_PARTY_SECRET);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
